package de.plushnikov.intellij.plugin.processor.handler.singular; import com.intellij.openapi.project.Project; import com.intellij.psi.CommonClassNames; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiField; import com.intellij.psi.PsiManager; import com.intellij.psi.PsiModifier; import com.intellij.psi.PsiSubstitutor; import com.intellij.psi.PsiType; import com.intellij.psi.PsiVariable; import de.plushnikov.intellij.plugin.processor.field.AccessorsInfo; import de.plushnikov.intellij.plugin.psi.LombokLightFieldBuilder; import de.plushnikov.intellij.plugin.psi.LombokLightMethodBuilder; import de.plushnikov.intellij.plugin.util.PsiTypeUtil; import org.jetbrains.annotations.NotNull; import java.text.MessageFormat; import java.util.List; class SingularMapHandler extends AbstractSingularHandler { private static final String KEY = "Key"; private static final String VALUE = "Value"; private static final String LOMBOK_KEY = "$key"; private static final String LOMBOK_VALUE = "$value"; SingularMapHandler(String qualifiedName, boolean shouldGenerateFullBodyBlock) { super(qualifiedName, shouldGenerateFullBodyBlock); } public void addBuilderField(@NotNull List<PsiField> fields, @NotNull PsiVariable psiVariable, @NotNull PsiClass innerClass, @NotNull AccessorsInfo accessorsInfo, @NotNull PsiSubstitutor substitutor) { final String fieldName = accessorsInfo.removePrefix(psiVariable.getName()); final Project project = psiVariable.getProject(); final PsiManager psiManager = psiVariable.getManager(); final PsiType psiFieldType = psiVariable.getType(); final PsiType keyType = PsiTypeUtil.extractOneElementType(psiFieldType, psiManager, CommonClassNames.JAVA_UTIL_MAP, 0); final PsiType valueType = PsiTypeUtil.extractOneElementType(psiFieldType, psiManager, CommonClassNames.JAVA_UTIL_MAP, 1); final PsiType builderFieldKeyType = getBuilderFieldType(keyType, project); fields.add(new LombokLightFieldBuilder(psiManager, fieldName + LOMBOK_KEY, builderFieldKeyType) .withModifier(PsiModifier.PRIVATE) .withNavigationElement(psiVariable) .withContainingClass(innerClass)); final PsiType builderFieldValueType = getBuilderFieldType(valueType, project); fields.add(new LombokLightFieldBuilder(psiManager, fieldName + LOMBOK_VALUE, builderFieldValueType) .withModifier(PsiModifier.PRIVATE) .withNavigationElement(psiVariable) .withContainingClass(innerClass)); } @NotNull protected PsiType getBuilderFieldType(@NotNull PsiType psiType, @NotNull Project project) { final PsiManager psiManager = PsiManager.getInstance(project); return PsiTypeUtil.createCollectionType(psiManager, CommonClassNames.JAVA_UTIL_ARRAY_LIST, psiType); } protected void addOneMethodParameter(@NotNull LombokLightMethodBuilder methodBuilder, @NotNull PsiType psiFieldType, @NotNull String singularName) { final PsiManager psiManager = methodBuilder.getManager(); final PsiType keyType = PsiTypeUtil.extractOneElementType(psiFieldType, psiManager, CommonClassNames.JAVA_UTIL_MAP, 0); final PsiType valueType = PsiTypeUtil.extractOneElementType(psiFieldType, psiManager, CommonClassNames.JAVA_UTIL_MAP, 1); methodBuilder.withParameter(singularName + KEY, keyType); methodBuilder.withParameter(singularName + VALUE, valueType); } protected void addAllMethodParameter(@NotNull LombokLightMethodBuilder methodBuilder, @NotNull PsiType psiFieldType, @NotNull String singularName) { final PsiManager psiManager = methodBuilder.getManager(); final PsiType keyType = PsiTypeUtil.extractAllElementType(psiFieldType, psiManager, CommonClassNames.JAVA_UTIL_MAP, 0); final PsiType valueType = PsiTypeUtil.extractAllElementType(psiFieldType, psiManager, CommonClassNames.JAVA_UTIL_MAP, 1); final PsiType collectionType = PsiTypeUtil.createCollectionType(psiManager, CommonClassNames.JAVA_UTIL_MAP, keyType, valueType); methodBuilder.withParameter(singularName, collectionType); } protected String getClearMethodBody(String psiFieldName, boolean fluentBuilder) { final String codeBlockTemplate = "if (this.{0}" + LOMBOK_KEY + " != null) '{'\n this.{0}" + LOMBOK_KEY + ".clear();\n " + " this.{0}" + LOMBOK_VALUE + ".clear(); '}'\n {1}"; return MessageFormat.format(codeBlockTemplate, psiFieldName, fluentBuilder ? "\nreturn this;" : ""); } protected String getOneMethodBody(@NotNull String singularName, @NotNull String psiFieldName, @NotNull PsiType psiFieldType, @NotNull PsiManager psiManager, boolean fluentBuilder) { final String codeBlockTemplate = "if (this.{0}" + LOMBOK_KEY + " == null) '{' \n" + "this.{0}" + LOMBOK_KEY + " = new java.util.ArrayList<{3}>(); \n" + "this.{0}" + LOMBOK_VALUE + " = new java.util.ArrayList<{4}>(); \n" + "'}' \n" + "this.{0}" + LOMBOK_KEY + ".add({1}" + KEY + ");\n" + "this.{0}" + LOMBOK_VALUE + ".add({1}" + VALUE + ");" + "{2}"; final PsiType keyType = PsiTypeUtil.extractOneElementType(psiFieldType, psiManager, CommonClassNames.JAVA_UTIL_MAP, 0); final PsiType valueType = PsiTypeUtil.extractOneElementType(psiFieldType, psiManager, CommonClassNames.JAVA_UTIL_MAP, 1); return MessageFormat.format(codeBlockTemplate, psiFieldName, singularName, fluentBuilder ? "\nreturn this;" : "", keyType.getCanonicalText(false), valueType.getCanonicalText(false)); } protected String getAllMethodBody(@NotNull String singularName, @NotNull PsiType psiFieldType, @NotNull PsiManager psiManager, boolean fluentBuilder) { final String codeBlockTemplate = "if (this.{0}" + LOMBOK_KEY + " == null) '{' \n" + "this.{0}" + LOMBOK_KEY + " = new java.util.ArrayList<{2}>(); \n" + "this.{0}" + LOMBOK_VALUE + " = new java.util.ArrayList<{3}>(); \n" + "'}' \n" + "for (final java.util.Map.Entry<{4},{5}> $lombokEntry : {0}.entrySet()) '{'\n" + "this.{0}" + LOMBOK_KEY + ".add($lombokEntry.getKey());\n" + "this.{0}" + LOMBOK_VALUE + ".add($lombokEntry.getValue());\n" + "'}'{1}"; final PsiType keyType = PsiTypeUtil.extractOneElementType(psiFieldType, psiManager, CommonClassNames.JAVA_UTIL_MAP, 0); final PsiType valueType = PsiTypeUtil.extractOneElementType(psiFieldType, psiManager, CommonClassNames.JAVA_UTIL_MAP, 1); final PsiType keyIterType = PsiTypeUtil.extractAllElementType(psiFieldType, psiManager, CommonClassNames.JAVA_UTIL_MAP, 0); final PsiType valueIterType = PsiTypeUtil.extractAllElementType(psiFieldType, psiManager, CommonClassNames.JAVA_UTIL_MAP, 1); return MessageFormat.format(codeBlockTemplate, singularName, fluentBuilder ? "\nreturn this;" : "", keyType.getCanonicalText(false), valueType.getCanonicalText(false), keyIterType.getCanonicalText(false), valueIterType.getCanonicalText(false)); } @Override public void appendBuildPrepare(@NotNull StringBuilder buildMethodCode, @NotNull PsiVariable psiVariable, @NotNull String fieldName) { final PsiManager psiManager = psiVariable.getManager(); final PsiType psiFieldType = psiVariable.getType(); final PsiType keyType = PsiTypeUtil.extractOneElementType(psiFieldType, psiManager, CommonClassNames.JAVA_UTIL_MAP, 0); final PsiType valueType = PsiTypeUtil.extractOneElementType(psiFieldType, psiManager, CommonClassNames.JAVA_UTIL_MAP, 1); final String selectedFormat; if (collectionQualifiedName.equals(SingularCollectionClassNames.JAVA_UTIL_SORTED_MAP)) { selectedFormat = "java.util.SortedMap<{1}, {2}> {0} = new java.util.TreeMap<{1}, {2}>();\n" + " if (this.{0}$key != null) for (int $i = 0; $i < (this.{0}$key == null ? 0 : this.{0}$key.size()); $i++) {0}.put(this.{0}$key.get($i), this.{0}$value.get($i));\n" + " {0} = java.util.Collections.unmodifiableSortedMap({0});\n"; } else if (collectionQualifiedName.equals(SingularCollectionClassNames.JAVA_UTIL_NAVIGABLE_MAP)) { selectedFormat = "java.util.NavigableMap<{1}, {2}> {0} = new java.util.TreeMap<{1}, {2}>();\n" + " if (this.{0}$key != null) for (int $i = 0; $i < (this.{0}$key == null ? 0 : this.{0}$key.size()); $i++) {0}.put(this.{0}$key.get($i), this.{0}$value.get($i));\n" + " {0} = java.util.Collections.unmodifiableNavigableMap({0});\n"; } else { selectedFormat = "java.util.Map<{1}, {2}> {0};\n" + " switch (this.{0}$key == null ? 0 : this.{0}$key.size()) '{'\n" + " case 0:\n" + " {0} = java.util.Collections.emptyMap();\n" + " break;\n" + " case 1:\n" + " {0} = java.util.Collections.singletonMap(this.{0}$key.get(0), this.{0}$value.get(0));\n" + " break;\n" + " default:\n" + " {0} = new java.util.LinkedHashMap<{1}, {2}>(this.{0}$key.size() < 1073741824 ? 1 + this.{0}$key.size() + (this.{0}$key.size() - 3) / 3 : java.lang.Integer.MAX_VALUE);\n" + " for (int $i = 0; $i < this.{0}$key.size(); $i++) {0}.put(this.{0}$key.get($i), this.{0}$value.get($i));\n" + " {0} = java.util.Collections.unmodifiableMap({0});\n" + " '}'\n"; } buildMethodCode.append(MessageFormat.format(selectedFormat, fieldName, keyType.getCanonicalText(false), valueType.getCanonicalText(false), collectionQualifiedName)); } }